<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// $Id: RBAC.class.php 2947 2012-05-13 15:57:48Z liu21st@gmail.com $

/**
 +------------------------------------------------------------------------------
 * 基于角色的数据库方式验证类
 +------------------------------------------------------------------------------
 * @category   ORG
 * @package  ORG
 * @subpackage  Util
 * @author    liu21st <liu21st@gmail.com>
 * @version   $Id: RBAC.class.php 2947 2012-05-13 15:57:48Z liu21st@gmail.com $
 +------------------------------------------------------------------------------
 */
// 配置文件增加设置
// USER_AUTH_ON 是否需要认证
// USER_AUTH_TYPE 认证类型
// USER_AUTH_KEY 认证识别号
// REQUIRE_AUTH_MODULE  需要认证模块
// NOT_AUTH_MODULE 无需认证模块
// USER_AUTH_GATEWAY 认证网关
// RBAC_DB_DSN  数据库连接DSN
// RBAC_ROLE_TABLE 角色表名称
// RBAC_USER_TABLE 用户表名称
// RBAC_ACCESS_TABLE 权限表名称
// RBAC_NODE_TABLE 节点表名称

class RBAC {

	/**
	 * 认证方法
	 */
    static public function authenticate($map,$model='') {
    	
        if(empty($model)) $model =  C('USER_AUTH_MODEL');
        
        //使用给定的Map进行认证
        return M($model)->where($map)->find();
    }

	/**
	 * 登陆检查
	 */
	static public function checkLogin() {
		
		if(!$_SESSION[C('USER_AUTH_KEY')]) {
			
			$model = C('USER_AUTH_MODEL');
			$model = D($model)->clearLoginSession();
			RBAC::redirect(PHP_FILE.C('USER_AUTH_GATEWAY'));
		}      
        return true;
	}
	
	/**
	 * 父页面进行跳转
	 */
	static public function redirect($url){
		
		$html  = "";
		$html .= "<script>";
		$html .= "window.parent.location='".$url."';";
		//$html .= "window.parent.location=window.location";
		$html .= "</script>";
		exit($html);
	}


    /**
     * 检查当前操作是否需要认证
     */
    static function checkAccess() {
    	
        //如果项目要求认证，并且当前模块需要认证，则进行权限认证
        if( C('USER_AUTH_ON') ){
			$_module	=	array();
			$_action	=	array();
            if("" != C('REQUIRE_AUTH_MODULE')) {
                //需要认证的模块
                $_module['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_MODULE')));
            }else {
                //无需认证的模块
                $_module['no'] = explode(',',strtoupper(C('NOT_AUTH_MODULE')));
            }
            //检查当前模块是否需要认证
            if((!empty($_module['no']) && !in_array(strtoupper(MODULE_NAME),$_module['no'])) || (!empty($_module['yes']) && in_array(strtoupper(MODULE_NAME),$_module['yes']))) {
				if("" != C('REQUIRE_AUTH_ACTION')) {
					//需要认证的操作
					$_action['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_ACTION')));
				}else {
					//无需认证的操作
					$_action['no'] = explode(',',strtoupper(C('NOT_AUTH_ACTION')));
				}
				//检查当前操作是否需要认证
				if((!empty($_action['no']) && !in_array(strtoupper(ACTION_NAME),$_action['no'])) || (!empty($_action['yes']) && in_array(strtoupper(ACTION_NAME),$_action['yes']))) {
					return true;
				}else {
					return false;
				}
            }else {
                return false;
            }
        }
        return false;
    }


    /**
     * 权限认证的过滤器方法
     */
    static public function AccessDecision($appName=APP_NAME) {
    	
        //检查是否需要认证
        if(RBAC::checkAccess()) {
            //存在认证识别号，则进行进一步的访问决策
            $accessGuid   =   md5($appName.MODULE_NAME.ACTION_NAME);
            if(empty($_SESSION[C('ADMIN_AUTH_KEY')])) {
                if(C('USER_AUTH_TYPE')==2) {
                    //加强验证和即时验证模式 更加安全 后台权限修改可以即时生效
                    //通过数据库进行访问检查
                    $accessList = RBAC::getAccessList($_SESSION[C('USER_AUTH_KEY')]);
                }else {
                    // 如果是管理员或者当前操作已经认证过，无需再次认证
                    if(@$_SESSION[$accessGuid]) {
                        return true;
                    }
                    //登录验证模式，比较登录后保存的权限访问列表
                    $accessList = RBAC::getAccessAction();
                }
                //判断是否为组件化模式，如果是，验证其全模块名
                $module = defined('P_MODULE_NAME')?  P_MODULE_NAME   :   MODULE_NAME;
                if(!isset($accessList[strtoupper($appName)][strtoupper($module)][strtoupper(ACTION_NAME)])) {
                    $_SESSION[$accessGuid]  =   false;
                    return false;
                }
                else {
                    $_SESSION[$accessGuid]	=	true;
                }
            }else{
                //管理员无需认证
				return true;
			}
        }
        return true;
    }
	
	
	/**
	 * 读取角色的Menu
	 */
	static public function getAccessMenu(){
		
		  $roleid = $_SESSION[C('USER_AUTH_ROLE')];
		  $userid = $_SESSION[C('USER_AUTH_KEY')];
		  $value  =  S("Hdmin_Menu_".$userid);
		  
		  if(empty($value)){
			  $value = RBAC::saveAccessMenu($roleid,$userid);
		  }
		  return $value;
	}
	
	/**
	 * 存储角色的Menu
	 */
	static public function saveAccessMenu($roleid,$userid){
		
		$value = RBAC::getMenuList($roleid,$userid);
	    S("Hdmin_Menu_".$userid, $value, 60*30);
		return $value;
	}
	
	/**
	 * 取得当前认证角色的所有菜单和快捷方式
	 * @param integer $role   角色Id
	 * @param integer $userid 用户Id
	 * @access public
	 * @return array("menu","quick")
	 */
	static function getMenuList($roleid,$userid){
		
		$admin = $_SESSION[C('ADMIN_AUTH_KEY')];
		$map   = array("role"=>$roleid, "userid"=>$userid);
		$json  = sendRest("BDC/Node/rbacMenu", $map);//dump($json);exit();

		$list  = $json["data"];
		$menu  = $list["menu"];
		$quick = $list["quick"];
	
		foreach($menu as $a=>$b){
			$pid   = $b['id'];
			$level = $b['level'];
			$b['config'] = json_decode($b["config"],true);
			
			if($level == 1){
				$rows[$pid] = $b ;
				foreach($menu as $k=>$v){
					if($pid == $v['pid']){
						$v['config'] = json_decode($v["config"],true);
						$rows[$pid]['child'][] = $v ;
					}
				}
			}

			$all[] = $b;
		}
		$list["menu"] = $all;
		$list["desk"] = $rows;
			
		if($admin && empty($quick)){
			$list['quick'] = RBAC::dealQuickMenu($all);
		}else{
			if($quick){
				foreach ($quick as $k=>$v){
					$v['config'] = json_decode($v["config"],true);
					$quicks[] = $v;
				}
				$list['quick'] = $quicks;
			}
		}
		return $list;
	}
	
	/**
	 * 初始化管理员的快捷菜单
	 */
	static function dealQuickMenu($menu){
		
		foreach($menu as $k=>$v){
			
			if($v['type'] == 2){
				$rows[] = $v;
			}
		}
		return $rows;
	}
	
	/**
	 * 初始化管理员的全部菜单
	 */
	static function dealAllMenu($menu){
		
		
		foreach($menu as $a=>$b){
			
			$pid   = $b['id'];
			$level = $b['level'];
			
			if($level == 1){
				
				$rows[$pid] = $b ;
				foreach($menu as $k=>$v){
					
					if($pid == $v['pid']){
						$rows[$pid]['child'][] = $v ;
					}
				}
			}
		}
		return $rows;
	}
	
	
	/**
	 * 读取用户认证的action
	 */
	static function getAccessAction(){
		
		$userid = $_SESSION[C('USER_AUTH_KEY')];
		$value  = S("Hdmin_Access_".$userid);
		if(empty($value)){
			$value = RBAC::saveAccessAction($userid);
		}//dump($value);
		return $value; 
	}
	
	/**
	 * 设置用户认证的action
	 */
	static function saveAccessAction($userid){
		
		$value = RBAC::getAccessList($userid);
		S("Hdmin_Access_".$userid, $value, 60*30);
		return $value;
	}
	
	/**
     * 取得当前角色的所有权限列表
     * @param integer $userid 用户Id
     * @access public
     */
    static public function getAccessList($userid) {
    	
    	$root = strtoupper(C("RBAC_ROOT_KEY"));
    	$role = $_SESSION[C('USER_AUTH_ROLE')];
    	
		$map  = array("role"=>$role, "userid"=>$userid); 
    	$json = sendRest("BDC/Node/rbacNode",$map);
    	$list = $json["data"];
    	$one  = $list["one"];
    	$two  = $list["two"];
    	
    	$array = array(); 
    	foreach($one as $a=>$b){
    		$name = strtoupper($b["name"]);
    		$pid  = $b["id"];
    		foreach($two as $k=>$v){
    			if($pid == $v['tid']){
    				$action = strtoupper($v["name"]);
    				$array[$name][$action] = $v['id'];
    			}
    		}
    	}
    	$access[$root] = $array;
        return $access;
    }
	
}